package com.calculation.demo01;

import java.math.BigDecimal;

public class Test {
    public static void main(String[] args) {
        System.out.println("BigDecimal 学习");
        /**
         * 为什么学 BigDecimal ？浮点数计算存在精度问题
         * 是什么？用于对数字进行精确的运算（例如浮点数）
         * 怎么用？调用对应的api接口
         */
        // 1.浮点数计算存在精度问题
        double a = 0.1;
        double b = 0.1;
        double c = 0.2;
        double d = 0.3;
        System.out.println(a + b); // 0.2
        System.out.println(a + c); // 0.30000000000000004 存在精度问题
        System.out.println(d - a); // 0.19999999999999998
        System.out.println(c * b); // 0.020000000000000004
        System.out.println(d / a); // 2.9999999999999996

        // 测试
        System.out.println("=========");
        /**
         * ————————————————
         * 2、构造器描述
         * BigDecimal(int)      创建一个具有参数所指定整数值的对象。
         * BigDecimal(double)   创建一个具有参数所指定双精度值的对象。 不推荐使用 存在精度问题
         * BigDecimal(long)     创建一个具有参数所指定长整数值的对象。
         * BigDecimal(String)   创建一个具有参数所指定以字符串表示的数值的对象。推荐使用
         * ————————————————
         */
        // BigDecimal(double) 精度问题
        BigDecimal doubleStr = new BigDecimal(9.05);
        System.out.println(doubleStr); // 9.050000000000000710542735760100185871124267578125

        /**
         * 解决精度问题 还有其他两种方法
         * 1.把类型转成为字符串 toString();
         * 2.调用 BigDecimal.valueOf(); 静态方法
         */
        double price = 10.05;
        BigDecimal big_price = new BigDecimal(Double.toString(price));
        System.out.println(big_price); // 10.05
        BigDecimal big_money = BigDecimal.valueOf(10.10);
        System.out.println(big_money); // 10.1
        System.out.println("=====");
        /**
         * 通过上述的 使用案例，BigDecimal(double) 存在精度问题
         * 所以推荐使用 BigDecimal(String)
         */
        BigDecimal str = new BigDecimal("9.05");
        System.out.println(str); // 9.05 不存在精度问题
        System.out.println("====方法使用====");
        /**
         * add(BigDecimal)          BigDecimal对象中的值相加，然后返回这个对象。
         * subtract(BigDecimal)     BigDecimal对象中的值相减，然后返回这个对象。
         * multiply(BigDecimal)     BigDecimal对象中的值相乘，然后返回这个对象。
         * divide(BigDecimal)       BigDecimal对象中的值相除，然后返回这个对象。
         * toString()               将BigDecimal对象的数值转换成字符串。
         * doubleValue()            将BigDecimal对象中的值以 double类型 返回。
         * floatValue()             将BigDecimal对象中的值以 float类型 返回。
         * longValue()              将BigDecimal对象中的值以 long类型 返回。
         * intValue()               将BigDecimal对象中的值以 int整数类型 返回。
         * ————————————————
         */
        // BigDecimal 是一个引用类型，所以普通的 传统的+、-、*、/等算术运算符 不能使用了。
        BigDecimal first  = new BigDecimal("36");
        BigDecimal second = new BigDecimal("12");
        BigDecimal third = new BigDecimal("5.03");
        System.out.println("加法计算： "+first.add(second)); // 48
        BigDecimal add_num = first.add(second);
        System.out.println(add_num); // 48
        System.out.println("减法计算： "+first.subtract(second)); // 24
        System.out.println("乘法计算："+first.multiply(third)); // 181.08
        System.out.println("除法计算："+first.divide(second)); // 3
        /**
         * 这边特别提一下，如果进行除法运算的时候，结果不能整除，有余数，这个时候会报java.lang.ArithmeticException（运算异常）:
         *
         * 这边我们要避免这个错误产生，在进行除法运算的时候，针对可能出现的小数产生的计算，必须要多传两个参数
         *
         * divide(BigDecimal，scale 保留小数点后几位小数，舍入模式)
         * ROUND_CEILING     向正无穷方向舍入
         * ROUND_DOWN       舍弃保留小数位的后面数字 111.1934567 ，保留一位：111.1 -- 常用
         * ROUND_FLOOR      向负无穷方向舍入
         * ROUND_HALF_DOWN  若舍弃部分 ( > .5)  ROUND_UP（向上舍入）；否则，作 ROUND_DOWN（向下舍入）。例如 1.55 保留一位小数结果为1.5 保留两位小数 1.55
         *                  1.675 保留两位小数 1.67，1.673 保留两位小数 1.67
         * ROUND_HALF_EVEN  保留位数是奇数，使用ROUND_HALF_UP，如果是偶数，使用ROUND_HALF_DOWN
         * ROUND_HALF_UP   若舍弃部分 (>=.5)，则作 ROUND_UP（向上舍入）；否则，作 ROUND_DOWN（向下舍入）。例如 1.55保留一位小数结果为1.6,保留两位小数 1.56
         *                 1.675 保留两位小数 1.68 ，1.673 保留两位小数 1.67
         * ROUND_UNNECESSARY 计算结果是精确的，不需要舍入模式，主要在美国使用。
         * ROUND_UP        向远离0的方向舍入
         *
         * 注意：常用 ROUND_HALF_DOWN 和 ROUND_HALF_UP
         */
        System.out.println("除法计算 保留两位小数："+first.divide(third,2,BigDecimal.ROUND_HALF_UP)); // 四舍五入 7.16
        System.out.println("=====舍入模式======");

        BigDecimal big_num = BigDecimal.valueOf(10);
        BigDecimal big_double = new BigDecimal(Double.toString(3));
        System.out.println("ROUND_CEILING  -------"+big_num.divide(big_double,2,BigDecimal.ROUND_CEILING)); // 3.34
        System.out.println("ROUND_DOWN  ------"+big_num.divide(big_double,2,BigDecimal.ROUND_DOWN)); // 向下取 3.33
        System.out.println("ROUND_FLOOR  ------"+big_num.divide(big_double,2,BigDecimal.ROUND_FLOOR)); // 向下取 3.33
        System.out.println("ROUND_HALF_UP  ------"+big_num.divide(big_double,2,BigDecimal.ROUND_HALF_UP)); // 向上 四舍五入 3.33
        BigDecimal bg = new BigDecimal("3.102");
        BigDecimal bg2 = new BigDecimal("2");
        System.out.println(bg.divide(bg2,2,BigDecimal.ROUND_HALF_DOWN));
        System.out.println(bg.divide(bg2,2,BigDecimal.ROUND_HALF_UP));
        System.out.println(bg.divide(bg2,2,BigDecimal.ROUND_HALF_EVEN));
        System.out.println("=====舍入模式======");
        // 其他测试
        double abc = 1.233;
        float f = 3.3f;
        int def = 10;
        // double 和 float 类型的数据，使用 toString(a) 方法,将 double 类型转换成 String 类型
        BigDecimal big_d = new BigDecimal(Double.toString(abc));
        // float
        BigDecimal big_f = new BigDecimal(Float.toString(f));
        System.out.println("乘法："+big_f.multiply(big_d)); // 4.0689
        // 除法 必须保留两位小数 向下保留两位小数
        System.out.println("除法："+big_f.divide(big_d,2,BigDecimal.ROUND_HALF_DOWN)); // 2.68
        // int
        BigDecimal big_int = new BigDecimal(def);
        System.out.println(big_d.intValue());
        System.out.println(big_d.toString());
        System.out.println(big_d.doubleValue());
        System.out.println(big_d.longValue());
        System.out.println(big_d.floatValue());
        System.out.println("=========");
        System.out.println(big_int.doubleValue());
        System.out.println(big_int.floatValue());
    }
}
